home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / DirectShow / DMO / GargleDMO / MedParamBase / param.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  16.3 KB  |  576 lines

  1. //------------------------------------------------------------------------------
  2. // File: Param.cpp
  3. //
  4. // Desc: DirectShow sample code - definition of CParamsManager class.
  5. //
  6. // Copyright (c) 1999-2001 Microsoft Corporation.  All rights reserved.
  7. //------------------------------------------------------------------------------
  8.  
  9.  
  10. #include <windows.h>
  11. #include <medparam.h>
  12. #include "alist.h"
  13. #include "param.h"
  14. #include "dmerror.h"
  15. #include "param.h"
  16. #include "math.h"
  17. #include "validate.h"
  18.  
  19. // Disable some /W4 level warnings
  20. #pragma warning(disable:4296 4100 4505)
  21.  
  22.  
  23. CCurveList::~CCurveList()
  24. {
  25.     while(this->GetHead())
  26.     {
  27.         delete this->RemoveHead();
  28.     }
  29. }
  30.  
  31. CParamsManager::CParamsManager()
  32.   
  33. {
  34.     m_fDirty = FALSE;
  35.     m_cTimeFormats = 0;
  36.     m_pguidTimeFormats = NULL;
  37.     m_guidCurrentTimeFormat = GUID_NULL;
  38.     m_cParams = 0;
  39.     m_pCurveLists = NULL;
  40.     m_pParamInfos = NULL;
  41.     m_dwActiveBits = 0;
  42.     InitializeCriticalSection(&m_ParamsCriticalSection);
  43. }
  44.  
  45. CParamsManager::~CParamsManager()
  46. {
  47.     delete[] m_pguidTimeFormats;
  48.     delete[] m_pCurveLists;
  49.     delete[] m_pParamInfos;
  50.     DeleteCriticalSection(&m_ParamsCriticalSection);
  51. }
  52.  
  53. HRESULT CParamsManager::InitParams(DWORD cTimeFormats, const GUID *pguidTimeFormats, DWORD dwFormatIndex, MP_TIMEDATA mptdTimeData, DWORD cParams, ParamInfo *pParamInfo)
  54. {
  55.     //check that the index is in a valid range
  56.     if (0 > dwFormatIndex || dwFormatIndex >= cTimeFormats || cParams > sizeof(DWORD) * 8)
  57.         return E_INVALIDARG;
  58.         
  59.     m_pCurveLists = new CCurveList[cParams];
  60.     if (!m_pCurveLists)
  61.         return E_OUTOFMEMORY;
  62.  
  63.     // save the time formats
  64.     m_pguidTimeFormats = new GUID[cTimeFormats];
  65.     if (!m_pguidTimeFormats)
  66.         return E_OUTOFMEMORY;
  67.         
  68.     for (DWORD dwIndex = 0; dwIndex < cTimeFormats; dwIndex++)
  69.     {
  70.         memcpy(&m_pguidTimeFormats[dwIndex], &pguidTimeFormats[dwIndex], sizeof(*pguidTimeFormats));
  71.     }
  72.  
  73.     // save the count of formats
  74.     m_cTimeFormats = cTimeFormats;
  75.  
  76.     // save the current time format
  77.     m_guidCurrentTimeFormat = m_pguidTimeFormats[dwFormatIndex];
  78.  
  79.     // save the TimeData
  80.     m_mptdCurrentTimeData = mptdTimeData;
  81.  
  82.     // save the parameter info
  83.     m_pParamInfos
  84.     = new ParamInfo[cParams];
  85.     if (!m_pParamInfos)
  86.         return E_OUTOFMEMORY;
  87.     for (dwIndex = 0; dwIndex < cParams; dwIndex++)
  88.     {
  89.         if (pParamInfo[dwIndex].dwIndex < cParams)
  90.         {
  91.             memcpy(&m_pParamInfos[pParamInfo[dwIndex].dwIndex],&pParamInfo[dwIndex],sizeof(ParamInfo));
  92.         }
  93.     }
  94.     m_cParams = cParams;
  95.  
  96.     return S_OK;
  97. }
  98.  
  99. HRESULT CParamsManager::GetParamCount(DWORD *pdwParams)
  100.  
  101. {
  102.     if (pdwParams == NULL)
  103.         return E_POINTER;
  104.     
  105.     *pdwParams = m_cParams;
  106.     return S_OK;
  107. }
  108.  
  109. HRESULT CParamsManager::GetParamInfo(DWORD dwParamIndex,MP_PARAMINFO *pInfo)
  110.  
  111. {
  112.     if (!pInfo)
  113.     {
  114.         return E_POINTER;
  115.     }
  116.     if (dwParamIndex < m_cParams)
  117.     {
  118.         *pInfo = m_pParamInfos[dwParamIndex].MParamInfo;
  119.         return S_OK;
  120.     }
  121.     else
  122.     {
  123.         return E_INVALIDARG;
  124.     }
  125. }
  126.  
  127. HRESULT CParamsManager::GetParamText(DWORD dwParamIndex,WCHAR **ppwchText)
  128.  
  129. {
  130.     if (!ppwchText)
  131.     {
  132.         return E_POINTER;
  133.     }
  134.     if (dwParamIndex < m_cParams)
  135.     {
  136.         // write string of format: "Label\0Unit\0Enums1\0Enum2\0...EnumN\0\0"
  137.         ParamInfo &pinfo = m_pParamInfos[dwParamIndex];
  138.         int iUnit = wcslen(pinfo.MParamInfo.szLabel) + 1; // begin writing unit text here
  139.         int iEnums = iUnit + wcslen(pinfo.MParamInfo.szUnitText) + 1; // begin writing enum text here
  140.         int iEnd = iEnums + wcslen(pinfo.pwchText) + 1; // write the final (second) null terminator here
  141.         WCHAR *pwsz = static_cast<WCHAR *>(CoTaskMemAlloc((iEnd + 1) * sizeof(WCHAR)));
  142.         if (!pwsz)
  143.             return E_OUTOFMEMORY;
  144.  
  145.         // wcscpy will write into various points of the string, neatly terminating each with a null
  146.         wcscpy(pwsz, pinfo.MParamInfo.szLabel);
  147.         wcscpy(pwsz + iUnit, pinfo.MParamInfo.szUnitText);
  148.         wcscpy(pwsz + iEnums, pinfo.pwchText);
  149.  
  150.         // The text field was defined with commas to separate the enum values.
  151.         // Replace them with NULL characters now.
  152.         for (WCHAR *pwch = pwsz + iEnums; *pwch; ++pwch)
  153.         {
  154.             if (*pwch == L',')
  155.                 *pwch = L'\0';
  156.         }
  157.  
  158.         pwsz[iEnd] = L'\0';
  159.         
  160.         *ppwchText = pwsz;
  161.         return S_OK;
  162.     }
  163.     else
  164.     {
  165.         return E_INVALIDARG;
  166.     }
  167. }
  168.  
  169. HRESULT CParamsManager::GetNumTimeFormats(DWORD *pdwNumTimeFormats)
  170.  
  171. {
  172.     if (!pdwNumTimeFormats)
  173.     {
  174.         return E_POINTER;
  175.     }
  176.     *pdwNumTimeFormats = m_cTimeFormats;
  177.     return S_OK;
  178. }
  179.  
  180. HRESULT CParamsManager::GetSupportedTimeFormat(DWORD dwFormatIndex,GUID *pguidTimeFormat)
  181.  
  182. {
  183.     if (!pguidTimeFormat)
  184.     {
  185.         return E_POINTER;
  186.     }
  187.     if (dwFormatIndex >= m_cTimeFormats)
  188.     {
  189.         return E_INVALIDARG;
  190.     }
  191.     *pguidTimeFormat = m_pguidTimeFormats[dwFormatIndex];
  192.     return S_OK;
  193. }
  194.  
  195. HRESULT CParamsManager::GetCurrentTimeFormat( GUID *pguidTimeFormat,MP_TIMEDATA *pTimeData)
  196.  
  197. {
  198.     HRESULT hr=S_OK;
  199.     
  200.     // Parameter Validation
  201.     if ((pguidTimeFormat == NULL) || (pTimeData == NULL))
  202.     {
  203.         hr = E_POINTER;
  204.     }
  205.  
  206.     // Return the values
  207.     if (SUCCEEDED(hr))
  208.     {
  209.         *pguidTimeFormat = m_guidCurrentTimeFormat;
  210.         *pTimeData = m_mptdCurrentTimeData;
  211.     }
  212.     
  213.     return hr;
  214. }
  215.  
  216.  
  217. HRESULT CParamsManager::CopyParamsFromSource( CParamsManager * pSource)
  218.  
  219. {
  220.     HRESULT hr = S_OK;
  221.     DWORD dwIndex;
  222.  
  223.     for (dwIndex = 0; dwIndex < m_cTimeFormats; dwIndex++)
  224.     {
  225.         if (pSource->m_guidCurrentTimeFormat == m_pguidTimeFormats[dwIndex])
  226.         {
  227.             break;
  228.         }
  229.     }
  230.     
  231.     
  232.     hr = InitParams(pSource->m_cTimeFormats, pSource->m_pguidTimeFormats, dwIndex, pSource->m_mptdCurrentTimeData, pSource->m_cParams,pSource->m_pParamInfos);
  233.     if (SUCCEEDED(hr))
  234.     {
  235.         for (dwIndex = 0; dwIndex < m_cParams; dwIndex++)
  236.         {
  237.             CCurveItem *pCurve = pSource->m_pCurveLists[dwIndex].GetHead();
  238.             for (;pCurve;pCurve = pCurve->GetNext())
  239.             {
  240.                 CCurveItem *pNew = new CCurveItem;
  241.                 if (!pNew) 
  242.                 {
  243.                     return E_OUTOFMEMORY;
  244.                 }
  245.                 pNew->m_Envelope = pCurve->m_Envelope;
  246.                 m_pCurveLists[dwIndex].AddTail(pNew);
  247.             }
  248.         }
  249.     }
  250.     return hr;
  251. }
  252.  
  253. void
  254. CParamsManager ::UpdateActiveParams(REFERENCE_TIME rtTime, UpdateCallback &rThis)
  255. {
  256.     if (!m_dwActiveBits)
  257.         return; // nothing to recalc
  258.  
  259.     DWORD dwBit = 1;
  260.     for (DWORD dwIndex = 0; dwIndex < m_cParams; dwIndex++, dwBit = dwBit << 1)
  261.     {
  262.         if (m_dwActiveBits & dwBit)
  263.         {
  264.             float fVal = 0;
  265.             HRESULT hr = GetParamFloat(dwIndex, rtTime, &fVal);
  266.             rThis.SetParamUpdate(dwIndex, fVal);
  267.             if (hr == S_FALSE)
  268.                 m_dwActiveBits &= ~dwBit; // we're beyond the last curve, don't need to recalc next time
  269.  
  270.             //TraceI(6, "DMO value: time %I64d, param #%d, current value %hf\n", rtTime, dwIndex, fVal);
  271.         }
  272.     }
  273. }
  274.  
  275. inline float ValRange(float valToClip, float valMin, float valMax)
  276. {
  277.     return valToClip < valMin
  278.                 ? valMin
  279.                 : (valToClip > valMax ? valMax : valToClip);
  280. }
  281.  
  282. HRESULT CParamsManager::GetParamFloat(DWORD dwParamIndex,REFERENCE_TIME rtTime,float *pval)
  283. {
  284.     HRESULT hr = S_OK;
  285.  
  286.     if (dwParamIndex >= m_cParams)
  287.         return E_INVALIDARG;
  288.  
  289.     EnterCriticalSection(&m_ParamsCriticalSection);
  290.     CCurveList *pList = &m_pCurveLists[dwParamIndex];
  291.     ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
  292.  
  293.     // if no points, then neutral value
  294.     CCurveItem *pCurveHead = pList->GetHead();
  295.     if (!pCurveHead)
  296.     {
  297.         *pval = pInfo->MParamInfo.mpdNeutralValue;
  298.         LeaveCriticalSection(&m_ParamsCriticalSection);
  299.         return S_FALSE;
  300.     }
  301.  
  302.     // Find the curve during or before the requested time
  303.     // If the time is during a curve, we will use that.
  304.     // If not, we need the end value of the previous curve.
  305.     // Our list keeps these in backwards order, so we are scanning from the 
  306.     // highest point in time backwards.
  307.  
  308.     for (CCurveItem *pCurve = pCurveHead; pCurve && pCurve->m_Envelope.rtStart > rtTime;pCurve = pCurve->GetNext());
  309.  
  310.     // If there is no pCurve, there was no curve prior to or during rtTime. Give up.
  311.     if (!pCurve)
  312.     {
  313.         *pval = pInfo->MParamInfo.mpdNeutralValue;
  314.         LeaveCriticalSection(&m_ParamsCriticalSection);
  315.         return S_OK;
  316.     }
  317.     // Now, if pCurve ends before the requested time,
  318.     // return the final value of pCurve, since that will hold until the start of the next curve.
  319.     if (pCurve->m_Envelope.rtEnd < rtTime)
  320.     {
  321.         *pval = pCurve->m_Envelope.valEnd;
  322.         LeaveCriticalSection(&m_ParamsCriticalSection);
  323.         if (pCurve == pCurveHead)
  324.             return S_FALSE; // past last curve
  325.         else
  326.             return S_OK; // there are more curves ahead
  327.     }
  328.  
  329.     // If we get this far, the curve must bound rtTime.
  330.  
  331.     if (pCurve->m_Envelope.iCurve & MP_CURVE_JUMP)
  332.     {
  333.         *pval = pCurve->m_Envelope.valEnd;
  334.         LeaveCriticalSection(&m_ParamsCriticalSection);
  335.         return S_OK;
  336.     }
  337.  
  338.     REFERENCE_TIME rtTimeChange = pCurve->m_Envelope.rtEnd - pCurve->m_Envelope.rtStart;
  339.     REFERENCE_TIME rtTimeIntermediate = rtTime - pCurve->m_Envelope.rtStart; 
  340.  
  341.     float fltScalingX = static_cast<float>(rtTimeIntermediate) / rtTimeChange; // horizontal distance along curve between 0 and 1
  342.     float fltScalingY; // height of curve at that point between 0 and 1 based on curve function
  343.     switch (pCurve->m_Envelope.iCurve)
  344.     {
  345.     case MP_CURVE_SQUARE:
  346.         fltScalingY = fltScalingX * fltScalingX;
  347.         break;
  348.     case MP_CURVE_INVSQUARE:
  349.         fltScalingY = (float) sqrt(fltScalingX);
  350.         break;
  351.     case MP_CURVE_SINE:
  352.         // ºº Maybe we should have a lookup table here?
  353.         fltScalingY = (float) (sin(fltScalingX * 3.1415926535 - (3.1415926535/2)) + 1) / 2;
  354.         break;
  355.     case MP_CURVE_LINEAR:
  356.     default:
  357.         fltScalingY = fltScalingX;
  358.     }
  359.  
  360.     // Find out if we need to pull the start point from the previous curve,
  361.     // the default neutral value, or the current curve.
  362.     float fStartVal = pCurve->m_Envelope.valStart;
  363.     if (pCurve->m_Envelope.flags & MPF_ENVLP_BEGIN_NEUTRALVAL)
  364.     {
  365.         fStartVal = pInfo->MParamInfo.mpdNeutralValue;
  366.     }
  367.     // Currentval, if it exists, will override neutralval.
  368.     if (pCurve->m_Envelope.flags & MPF_ENVLP_BEGIN_CURRENTVAL)
  369.     {
  370.         // Take advantage of the fact that these are inserted in backwards order.
  371.         // Scan for the previous curve that ends before this time.
  372.         CCurveItem *pPrevious = pCurve->GetNext();
  373.            for (;pPrevious && pPrevious->m_Envelope.rtEnd > rtTime;pPrevious = pPrevious->GetNext());
  374.         if (pPrevious)
  375.         {
  376.             fStartVal = pPrevious->m_Envelope.valEnd;
  377.         }
  378.     }
  379.     
  380.     // Apply that scaling to the range of the actual points
  381.     *pval = (pCurve->m_Envelope.valEnd - fStartVal) * fltScalingY + fStartVal;
  382.  
  383.     LeaveCriticalSection(&m_ParamsCriticalSection);
  384.     return hr;
  385. }
  386.  
  387. HRESULT CParamsManager::GetParamInt(DWORD dwParamIndex,REFERENCE_TIME rt,long *pval)
  388.  
  389. {
  390.     HRESULT hr = E_POINTER;
  391.     if (pval)
  392.     {
  393.         float fVal;
  394.         hr = GetParamFloat(dwParamIndex,rt,&fVal);
  395.         if (SUCCEEDED(hr))
  396.         {
  397.             *pval = (long) (fVal + 1/2);    // Round.
  398.         }
  399.     }
  400.     return hr;
  401. }
  402.  
  403. //////////////////////////////////////////////////////////////////////
  404. // IMediaParams
  405.  
  406. HRESULT CParamsManager::GetParam(DWORD dwParamIndex,MP_DATA *pValue)
  407. {
  408.     V_INAME(CParams::GetParam);
  409.     V_PTR_WRITE(pValue, MP_DATA);
  410.  
  411.     if (dwParamIndex >= m_cParams)
  412.         return E_INVALIDARG;
  413.  
  414.     EnterCriticalSection(&m_ParamsCriticalSection);
  415.  
  416.     CCurveList *pList = &m_pCurveLists[dwParamIndex];
  417.     ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
  418.     // if no points, then neutral value
  419.     CCurveItem *pCurve = pList->GetHead();
  420.     if (pCurve)
  421.     {
  422.         *pValue = pCurve->m_Envelope.valEnd;
  423.     }
  424.     else
  425.     {
  426.         *pValue = pInfo->MParamInfo.mpdNeutralValue;
  427.     }
  428.     LeaveCriticalSection(&m_ParamsCriticalSection);
  429.     return S_OK;
  430. }
  431.  
  432. HRESULT CParamsManager::SetParam(DWORD dwParamIndex,MP_DATA value)
  433. {
  434.     V_INAME(CParams::SetParam);
  435.     
  436.     if (dwParamIndex >= m_cParams)
  437.         return E_INVALIDARG;
  438.  
  439.     EnterCriticalSection(&m_ParamsCriticalSection);
  440.     m_fDirty = TRUE;
  441.     CCurveList *pList = &m_pCurveLists[dwParamIndex];
  442.     // ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
  443.  
  444.     // If we've already got a list, just force the most recent curve item to this value.
  445.     // Otherwise, create a node and add it.
  446.     CCurveItem *pCurve = pList->GetHead();
  447.     if (!pCurve)
  448.     {
  449.         pCurve = new CCurveItem;
  450.         if (pCurve)
  451.         {
  452.             pCurve->m_Envelope.rtStart =    0x8000000000000000; // Max negative.
  453.             pCurve->m_Envelope.rtEnd =      0x7FFFFFFFFFFFFFFF; // Max positive.
  454.             pCurve->m_Envelope.flags = 0;
  455.             pList->AddHead(pCurve);
  456.         }
  457.         else 
  458.         {
  459.             LeaveCriticalSection(&m_ParamsCriticalSection);
  460.             return E_OUTOFMEMORY;
  461.         }
  462.     }
  463.     pCurve->m_Envelope.valStart = value;
  464.     pCurve->m_Envelope.valEnd = value;
  465.     pCurve->m_Envelope.iCurve = MP_CURVE_JUMP;
  466.     LeaveCriticalSection(&m_ParamsCriticalSection);
  467.  
  468.     return S_OK;
  469. }
  470.  
  471. HRESULT CParamsManager::AddEnvelope(
  472.         DWORD dwParamIndex,
  473.         DWORD cPoints,
  474.         MP_ENVELOPE_SEGMENT *ppEnvelope)
  475. {
  476.     V_INAME(CParams::AddEnvelope);
  477.     V_PTR_READ(ppEnvelope, *ppEnvelope);
  478.  
  479.     if (dwParamIndex >= m_cParams)
  480.         return E_INVALIDARG;
  481.  
  482.     if (!m_pParamInfos)
  483.         return DMUS_E_NOT_INIT;
  484.  
  485.     HRESULT hr = S_OK;
  486.     EnterCriticalSection(&m_ParamsCriticalSection);
  487.     m_fDirty = TRUE;
  488.  
  489.     CCurveList *pList = &m_pCurveLists[dwParamIndex];
  490.     ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
  491.  
  492.     DWORD dwCount;
  493.     for (dwCount = 0; dwCount < cPoints; dwCount++)
  494.     {
  495.         CCurveItem *pCurve = new CCurveItem;
  496.         if (!pCurve) 
  497.         {
  498.             hr = E_OUTOFMEMORY;
  499.             break;
  500.         }
  501.         pCurve->m_Envelope = ppEnvelope[dwCount];
  502.         pCurve->m_Envelope.valEnd = ValRange(pCurve->m_Envelope.valEnd, 
  503.             pInfo->MParamInfo.mpdMinValue, pInfo->MParamInfo.mpdMaxValue);
  504.         pCurve->m_Envelope.valStart = ValRange(pCurve->m_Envelope.valStart, 
  505.             pInfo->MParamInfo.mpdMinValue, pInfo->MParamInfo.mpdMaxValue);
  506.         pList->AddHead(pCurve);
  507.         m_dwActiveBits |= 1 << dwParamIndex; // next call to UpdateActiveParams will ensure the parameter's value is recalculated
  508.  
  509.         //TraceI(6, "DMO envelope: time %I64d-%I64d, param #%d, value %hf-%hf\n",
  510.         //        pCurve->m_Envelope.rtStart, pCurve->m_Envelope.rtEnd,
  511.         //        dwParamIndex, pCurve->m_Envelope.valStart, pCurve->m_Envelope.valEnd);
  512.     }
  513.  
  514.     LeaveCriticalSection(&m_ParamsCriticalSection);
  515.  
  516.     return hr;
  517. }
  518.  
  519. HRESULT CParamsManager::FlushEnvelope(
  520.         DWORD dwParamIndex,
  521.         REFERENCE_TIME refTimeStart,
  522.         REFERENCE_TIME refTimeEnd)
  523. {
  524.     if (dwParamIndex >= m_cParams)
  525.         return E_INVALIDARG;
  526.  
  527.     if (!m_pParamInfos)
  528.         return DMUS_E_NOT_INIT;
  529.  
  530.     if (refTimeStart >= refTimeEnd)
  531.         return E_INVALIDARG;
  532.  
  533.     EnterCriticalSection(&m_ParamsCriticalSection);
  534.     m_fDirty = TRUE;
  535.     CCurveList *pList = &m_pCurveLists[dwParamIndex];
  536.     // ParamInfo *pInfo = &m_pParamInfos[dwParamIndex];
  537.  
  538.     CCurveList TempList;
  539.     CCurveItem *pCurve;
  540.     while ((pCurve = pList->RemoveHead()) != 0)
  541.     {
  542.         if ((pCurve->m_Envelope.rtStart >= refTimeStart) && 
  543.             (pCurve->m_Envelope.rtEnd <= refTimeEnd))
  544.         {
  545.             delete pCurve;
  546.         }
  547.         else 
  548.         {
  549.             TempList.AddHead(pCurve);
  550.         }
  551.     }
  552.     while ((pCurve = TempList.RemoveHead()) != 0)
  553.     {
  554.         pList->AddHead(pCurve);
  555.     }
  556.     LeaveCriticalSection(&m_ParamsCriticalSection);
  557.  
  558.     return S_OK;
  559. }
  560.  
  561. HRESULT CParamsManager::SetTimeFormat(
  562.         GUID guidTimeFormat,
  563.         MP_TIMEDATA mpTimeData)
  564. {
  565.     for (DWORD dwIndex = 0; dwIndex < m_cTimeFormats; dwIndex++)
  566.     {
  567.         if (guidTimeFormat == m_pguidTimeFormats[dwIndex])
  568.         {
  569.             m_guidCurrentTimeFormat = m_pguidTimeFormats[dwIndex];
  570.             return S_OK;
  571.         }
  572.     }
  573.  
  574.     return E_INVALIDARG;
  575. }
  576.